#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include <arpa/inet.h>  //字节序转换接口头文件
#include <sys/socket.h>  //套接字接口头文件
#include <netinet/in.h>  //地址结构类型以及协议类型宏头文件

int main(int argc,char* argv[])
{
  if(argc!=3){
    printf("./udp_ser 192.168.2.2 9000\n");
    return -1;
  }
  uint16_t port=atoi(argv[2]);   //端口信息，uint16 属于 ipv4 数据类型----包含有2字节16位数据 ,atoi 将字符串转换为整数
  char* ip=argv[1] ;  //ip 地址信息

  //1、创建套接字
  //int socket(int domain, int type, int protocol);
  int sockfd=socket(AF_INET ,SOCK_DGRAM,IPPROTO_UDP);  
               //AF_INET 代表的是 ipv4 地址域类型，SOCK_DGRAM 表示数据报套接字-UDP，IPPROTO_UDP 表示 UDP 协议类型

	if(sockfd<0){
		perror("socket error!\n");
		return -1;
	}

	
	//2、为套接字绑定地址信息
  //int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
		
	struct sockaddr_in addr; //定义一个 IPV4 地址结构
	addr.sin_family=AF_INET;  //定义为 IPV4 地址域类型
	addr.sin_port=htons(port);  //ipv4 地址域类型为 uint16_t 对应 16 位----故 使用 htons 进行主机字节序端口到网络字节序端口的转换
	addr.sin_addr.s_addr=inet_addr(ip);  //将点分十进制字符串 IP 地址转换为整型IP地址
	socklen_t len=sizeof(struct sockaddr_in);

	int ret=bind(sockfd,(struct sockaddr*)&addr,len);
	if(ret<0){
		perror("bind error!\n");  //套接字绑定地址信息失败
		return -1;
	}

	//循环接收发送数据
	while(1){
		//接收信息
		//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
		char buff[1024]={0};  //接收到的信息存放地址
		struct sockaddr_in peer;  //从哪里接收到的信息
		socklen_t len=sizeof(struct sockaddr_in);  //接受的数据长度
		
		ssize_t ret= recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&peer,&len);
		if(ret<0){
			perror("recvfrom error!\n");
			return -1;	
		}
		

		char* peerip=inet_ntoa(peer.sin_addr);  //数据发送到哪里，将整形 IP 地址转换为点分十进制的 IP 地址
		uint16_t peerport=ntohs(peer.sin_port);   //ipv4 地址域类型为 uint16_t 含有 16 位数字-->ntohs，将网络字节端口转换为主机字节序端口

		printf("client[%s : %d] say:%s\n",peerip,peerport,buff);
		

		//发送信息
    //ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
		char data[1024]={0} ;  //要发送的数据存放位置
		printf("server say: ");
		fflush(stdout);
		scanf("%s",data);
		
		ret=sendto(sockfd,data,strlen(data),0,(struct sockaddr*)&peer,len);
		if(ret<0){
			perror("sendto error!\n");
			return -1;
		}

	}
	//关闭套接字
	close(sockfd);

  return 0;
}
